﻿/* 
   Copyright 2011 LUCA Studios LLC & John Evans

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

namespace LUCAStudios.Silverlight.Controls
{
    using System;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Markup;

    /// <summary>
    /// An item control for displaying content within a LUCATabWindow control
    /// </summary>
    [TemplateVisualState(Name = "MouseEnter", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Checked", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "UnChecked", GroupName = "CommonStates")]
    [TemplatePart(Name=ButtonCloseTab, Type=typeof(Button))]
    [ContentProperty("Content")]
    public class LUCATabItem : ControlBase
    {
        #region fields

        private static int _zindex;
        private bool _isChecked;
        private Button _closeButton;

        private const string ButtonCloseTab = "btnCloseTab";

        #endregion

        /// <summary>
        /// Fires when the LUCATabItem is closing
        /// </summary>
        public event EventHandler TabItemClosing;

        /// <summary>
        /// Constructor
        /// </summary>
        public LUCATabItem()
        {
            DefaultStyleKey = typeof (LUCATabItem);
        }

        /// <summary>
        /// Called when the LUCA control is loaded
        /// </summary>
        protected override void OnLoaded()
        {
            base.OnLoaded();
            SetCheckedState(true);
        }

        #region private

        private LUCATabWindow ParentWindow
        {
            get { return ContainerContext as LUCATabWindow; }
        }

        private IObservable<LUCATabItem> GetPeers()
        {
            if (ParentWindow == null) return Observable.Empty<LUCATabItem>();

            return ParentWindow
                    .FindAllElementsByType<LUCATabItem>()
                    .Where(o => o.Equals(this) == false);
        }

        private void SetDragEvents()
        {
            if (ParentWindow == null) return;

            if (ParentWindow.AllowReorder)
            {
                GetPeers()
                    .Subscribe(p => p.MouseEnter += PeerMouseEnter);
            }

            ParentWindow.DragHandle.MouseLeave += ChromeMouseLeave;
            ParentWindow.DragHandle.MouseLeftButtonUp += ChromeMouseLeftButtonUp;
        }

        private void ClearDragEvents()
        {
            if (ParentWindow == null) return;

            if (ParentWindow.AllowReorder)
            {
                GetPeers()
                    .Subscribe(p => p.MouseEnter -= PeerMouseEnter);
            }

            ParentWindow.DragHandle.MouseLeave -= ChromeMouseLeave;
            ParentWindow.DragHandle.MouseLeftButtonUp -= ChromeMouseLeftButtonUp;
        }

        private void ChromeMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ClearDragEvents();
        }

        private void ChromeMouseLeave(object sender, MouseEventArgs e)
        {
            ClearDragEvents();

            if (!((LUCATabWindow)ContainerContext).AllowDetachFrom) return;

            //clone the old LUCATabWindow's column/row definitions
            var ocd = LUCAStackPanel.GetColumnDefinition(ContainerContext);
            var ocr = LUCAStackPanel.GetRowDefinition(ContainerContext);
          
            var newWin = new LUCATabWindow
            {
                WindowID = Guid.NewGuid().ToString()
            };

            if (ocd != default(ColumnDefinition))
            {
                var ncd = new ColumnDefinition { Width = ocd.Width };
                LUCAStackPanel.SetColumnDefinition(newWin, ncd);
            }

            if (ocr != default(RowDefinition))
            {
                var nrw = new RowDefinition { Height = ocr.Height };
                LUCAStackPanel.SetRowDefinition(newWin, nrw);
            }

            this.Remove();

            newWin.AddChild(this);
            newWin.AddAndDrag(LayoutContext);
        }

        private void PeerMouseEnter(object sender, MouseEventArgs e)
        {
            var source = sender as LUCATabItem;
            if (source == null) return;

            ((LUCATabWindow) ContainerContext).SwapItems(this, source);
        }

        internal void SetCheckedState(bool isChecked)
        {
            if (!_isChecked && isChecked)
            {
                GetPeers()
                    .Subscribe(i => i.SetCheckedState(false));
                Canvas.SetZIndex(this, ++_zindex);
            }

            _isChecked = isChecked;
            VisualStateManager.GoToState(this, _isChecked ? "Checked" : "UnChecked", false);
        }

        private void InitEvents()
        {
            _closeButton.Click += CloseButtonClick;
        }

        private void DeInitEvents()
        {
            if (_closeButton == null) return;
            _closeButton.Click -= CloseButtonClick;
        }

        private void CloseButtonClick(object sender, RoutedEventArgs e)
        {
            if (TabItemClosing != null) TabItemClosing(this, new EventArgs());
            OnTabItemClosing();
        }

        protected virtual void OnTabItemClosing()
        {
            this.Remove();
        }

        #endregion

        

        #region properties

        /// <summary>
        /// A backing property for the Title Dependency Property
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof (string), typeof (LUCATabItem),
                                        new PropertyMetadata("no title"));


        /// <summary>
        /// A backing property for the CloseButtonVisibility Dependency Property
        /// </summary>
        public static readonly DependencyProperty CloseButtonVisibilityProperty =
            DependencyProperty.Register(
                "CloseButtonVisibility", typeof (Visibility), typeof (LUCATabItem),
                new PropertyMetadata(Visibility.Collapsed, OnCloseButtonVisbilityChanging));

        /// <summary>
        /// A backing property for the Content Dependency Property
        /// </summary>
        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof (object), typeof (LUCATabItem),
                                        new PropertyMetadata(default(object)));

        /// <summary>
        /// A Dependency Property that display the title of the LUCATabItem
        /// </summary>
        public string Title
        {
            get { return (string) GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// A dependency property that determines if the LUCATabItem's close button is visible or not
        /// </summary>
        public Visibility CloseButtonVisibility
        {
            get { return (Visibility) GetValue(CloseButtonVisibilityProperty); }
            set { SetValue(CloseButtonVisibilityProperty, value); }
        }

        /// <summary>
        /// A dependency property which holds the content displayed by the LUCATabItem
        /// </summary>
        public object Content
        {
            get { return GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        private static void OnCloseButtonVisbilityChanging(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            ((LUCATabItem) o).CloseButtonVisibility = (Visibility) e.NewValue;
        }

        #endregion

        #region overrides

        /// <summary>
        /// When overridden in a derived class, is invoked whenever application code or internal processes (such as a rebuilding layout pass) call <see cref="M:System.Windows.Controls.Control.ApplyTemplate"/>. In simplest terms, this means the method is called just before a UI element displays in an application. For more information, see Remarks.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            
            if (_closeButton != null) DeInitEvents();

            _closeButton = GetTemplateChild(ButtonCloseTab) as Button;
            if (_closeButton == null)
                throw new LUCAControlException("Expected control template reference to be set.");

            VisualStateManager.GoToState(this, _isChecked ? "Checked" : "UnChecked", false);
            InitEvents();
        }

        /// <summary>
        /// Called before the <see cref="E:System.Windows.UIElement.MouseLeftButtonDown"/> event occurs.
        /// </summary>
        /// <param name="e">The data for the event. </param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (ParentWindow == null) return;

            if (ParentWindow.Children.Count > 1)
            {
                SetDragEvents();
            }

            e.Handled = true;

            if (_isChecked) return;

            SetCheckedState(true);
            ParentWindow.UpdateToContentItem(this);
            OnSelected();
        }

        /// <summary>
        /// Called before the <see cref="E:System.Windows.UIElement.MouseLeftButtonUp"/> event occurs.
        /// </summary>
        /// <param name="e">The data for the event. </param>
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            ClearDragEvents();
            e.Handled = true;
        }

        /// <summary>
        /// Called before the <see cref="E:System.Windows.UIElement.MouseEnter"/> event occurs.
        /// </summary>
        /// <param name="e">The data for the event. </param>
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (!_isChecked)
                VisualStateManager.GoToState(this, "MouseEnter", false);
        }

        /// <summary>
        /// Called before the <see cref="E:System.Windows.UIElement.MouseLeave"/> event occurs.
        /// </summary>
        /// <param name="e">The data for the event. </param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (!_isChecked)
                VisualStateManager.GoToState(this, "UnChecked", false);
            base.OnMouseLeave(e);
        }

        #endregion
    }
}